<template>
  <div
    ref="codeEditBox"
    class="codeEditBox"
    :style="{ height: height }"
    :class="hightChange && 'codeEditBox1'"
  ></div>
</template>
<script lang="ts" setup>
  import 'monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp';
  import 'monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard';
  import * as monaco from 'monaco-editor';
  import monacoJsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
  import monacoCssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
  import monacoHtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
  import monacoTsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
  import monacoEditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
  import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/sql/sql.js';
  import { language as yamlLanguage } from 'monaco-editor/esm/vs/basic-languages/yaml/yaml.js';
  import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution';
  import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution';
  import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution';
  import { editorProps } from '@/types/monacoEditorType';
  // const isDev = process.env.NODE_ENV === 'development';
  const props = defineProps(editorProps);
  const emit = defineEmits<Emits>();
  interface Emits {
    (e: 'update:modelValue', val: any): void;
    (e: 'change', val: any): void;
    (e: 'editor-mounted', val: any): void;
  }
  self.MonacoEnvironment = {
    getWorker: function (workerId, label) {
      console.debug(`* lazy imported Monaco Editor worker id '${workerId}', label '${label}'`);
      // const getWorkerModule = (moduleUrl: string, label: string) =>
      //   new Worker(
      //     (self as any).MonacoEnvironment.getWorkerUrl(
      //       '/node_modules/monaco-editor/esm/vs/' + moduleUrl + '.js?worker',
      //       import.meta.url,
      //     ),
      //     {
      //       name: label,
      //       type: 'module',
      //     },
      //   );
      // switch (label) {
      //   case 'json':
      //     return !isDev
      //       ? getWorkerModule('language/json/json.worker?worker', label)
      //       : new monacoJsonWorker();
      //   case 'css':
      //   case 'scss':
      //   case 'less':
      //     return !isDev
      //       ? getWorkerModule('language/css/css.worker?worker', label)
      //       : new monacoCssWorker();
      //   case 'html':
      //   case 'handlebars':
      //   case 'razor':
      //     return !isDev
      //       ? getWorkerModule('language/html/html.worker?worker', label)
      //       : new monacoHtmlWorker();
      //   case 'typescript':
      //   case 'javascript':
      //     return !isDev
      //       ? getWorkerModule('language/typescript/ts.worker?worker', label)
      //       : new monacoTsWorker();
      //   default:
      //     return !isDev
      //       ? getWorkerModule('editor/editor.worker?worker', label)
      //       : new monacoEditorWorker();
      // }
      switch (label) {
        case 'json':
          return new monacoJsonWorker();
        case 'css':
        case 'scss':
        case 'less':
          return new monacoCssWorker();
        case 'html':
        case 'handlebars':
        case 'razor':
          return new monacoHtmlWorker();
        case 'typescript':
        case 'javascript':
          return new monacoTsWorker();
        default:
          return new monacoEditorWorker();
      }
    },
  };
  let editor: any;
  const codeEditBox = ref();

  const init = () => {
    monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: true,
      noSyntaxValidation: false,
    });
    monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
      target: monaco.languages.typescript.ScriptTarget.ES2016,
      allowNonTsExtensions: true,
    });
    monaco.languages.registerCompletionItemProvider('sql', {
      provideCompletionItems() {
        const suggestions: any = [];
        // 这个keywords就是sql.js文件中有的
        sqlLanguage.keywords.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Keyword,
            insertText: item,
          });
        });
        sqlLanguage.operators.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Operator,
            insertText: item,
          });
        });
        sqlLanguage.builtinFunctions.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Function,
            insertText: item,
          });
        });
        sqlLanguage.builtinVariables.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Variable,
            insertText: item,
          });
        });
        return {
          // 最后要返回一个数组
          suggestions,
        };
      },
    });

    monaco.languages.registerCompletionItemProvider('yaml', {
      provideCompletionItems() {
        const suggestions: any = [];
        // 这个keywords就是python.js文件中有的
        yamlLanguage.keywords.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Keyword,
            insertText: item,
          });
        });
        return {
          // 最后要返回一个数组
          suggestions,
        };
      },
    });

    editor = monaco.editor.create(codeEditBox.value, {
      value: props.modelValue, // 默认值
      language: props.language, // 语言
      readOnly: props.readOnly, // 是否只读
      theme: props.theme, // 主题
      ...props.options,
    });

    // 监听值的变化
    editor.onDidChangeModelContent(() => {
      const value = editor.getValue(); // 给父组件实时返回最新文本
      emit('update:modelValue', value);
      emit('change', value);
    });

    emit('editor-mounted', editor);
  };
  watch(
    () => props.modelValue,
    (newValue) => {
      if (editor) {
        const value = editor.getValue();
        if (newValue === null) newValue = '';
        if (newValue !== value) {
          editor.setValue(newValue);
        }
      }
    },
  );

  watch(
    () => props.options,
    (newValue) => {
      editor.updateOptions(newValue);
    },
    { deep: true },
  );
  watch(
    () => props.readOnly,
    () => {
      console.log('props.readOnly', props.readOnly);
      editor.updateOptions({ readOnly: props.readOnly });
    },
    { deep: true },
  );

  watch(
    () => props.language,
    (newValue) => {
      monaco.editor.setModelLanguage(editor.getModel()!, newValue);
    },
  );

  onBeforeUnmount(() => {
    editor.dispose();
  });

  onMounted(() => {
    init();
  });
</script>
<style lang="scss" scoped>
  .codeEditBox {
    width: 100%;
    flex: 1;
    min-height: 100px;
    // height: 200px;
    overflow-y: auto;
  }
  .codeEditBox1 {
    height: calc(100% - 323px);
  }
</style>
